// Copyright 1998-2016 Glenn McIntosh
// licensed under the GNU General Public Licence version 3

// include files
#include "random.h"

namespace math
{
uint32_t UniformRandom::Hash(uint32_t input)
{
	// four iterations of non-linear function to hash inputs
	uint32_t i0 = mSeed, i1 = input;
	uint32_t iA, iAl, iAh, iB;
	iA = i1 ^ 0xBAA96887;
	iAh = iA>>16;
	iAl = iA&0xFFFF;
	iB = iAl*iAl + ~(iAh*iAh) ^ 0x3B584B0F;
	i0 ^= (iB>>16 ^ iB<<16) + iAl*iAh;
	iA = i0 ^ 0x1E17D32C;
	iAh = iA>>16;
	iAl = iA&0xFFFF;
	iB = iAl*iAl + ~(iAh*iAh) ^ 0xF0C3E874;
	i1 ^= (iB>>16 ^ iB<<16) + iAl*iAh;
	iA = i1 ^ 0x03BCDC3C;
	iAh = iA>>16;
	iAl = iA&0xFFFF;
	iB = iAl*iAl + ~(iAh*iAh) ^ 0xC5A66955;
	i0 ^= (iB>>16 ^ iB<<16) + iAl*iAh;
	iA = i0 ^ 0x0F33D1B2;
	iAh = iA>>16;
	iAl = iA&0xFFFF;
	iB = iAl*iAl + ~(iAh*iAh) ^ 0xCA4655A7;
	i1 ^= (iB>>16 ^ iB<<16) + iAl*iAh;
	return i1;
}

UniformRandom::operator uint32_t()
{
	// hash
	return Hash(mIndex++);
}

UniformRandom::operator float()
{
	// hash and convert to a floating point number
	return static_cast<float>(Hash(mIndex++)&((1<<23)-1)) / 8388608.;
}

RandomBitSequence::operator bool()
{
	const uint32_t HighBit = 1u<<31;
	const uint32_t Mask = 1u<<0 ^ 1u<<3;

	// shift
	mBuffer <<= 1;

	// change masked bits
	if (mBuffer & HighBit)
		mBuffer ^= Mask;

	// return
	return mBuffer&1;
}
}
